"""
@Time : 2024/1/12 14:59
@Auth : Mr.Zhao
#Function : 关键字封装
"""
import json

import jsonpath
import requests
from common.begin import proxy
from common.Logging import logger
from common.Relation import relation
from urllib.parse import unquote
class MyAssertError(Exception):
    """自定义异常类"""

    def __init__(self, message: str):
        self.message = message
        super().__init__(self.message)

    def __str__(self):
        return self.message


class Inter:
    """接口测试关键字封装（操作层）"""

    def __init__(self):
        self.session = requests.session()
        self.relations_dict = {}
        self.resp = ""  # 请求结果保存
        self.json_resp = {}  # json请求结果保存
        self.url = ''  # 记录url前缀

    def __get_url_decode(self, params_dict):
        """url解码处理"""
        for key in params_dict.keys():
            if params_dict.get(key) and type(params_dict.get(key)) == str:
                params_dict[key] = unquote(params_dict.get(key))
        return True

    def __get_form_data(self, params: str = ''):
        """接口参数中data格式参数的解析(将url格式修改为字典)"""
        if not params:
            return None
        params_dict = {}  # 解析后的data接口参数，字典形式
        key_valus = params.split('&')
        for key_value in key_valus:
            kv = key_value.split('=')
            if len(kv) > 1:
                params_dict[kv[0]] = kv[1]
            else:
                params_dict[kv[0]] = None

        #解码
        logger.debug(f'data请求参数1：{params_dict}')

        self.__get_url_decode(params_dict)

        logger.debug(f'data请求参数2：{params_dict}')
        return params_dict

    def __get_form_data1(self, params: str = ''):
        """接口参数中data格式参数的解析(将url格式修改为字典)"""
        if not params:
            return None
        params_dict = {}  # 解析后的data接口参数，字典形式
        key_valus = params.split('&')
        for key_value in key_valus:
            try:
                idx = key_value.index('=')
                print(idx)
                params_dict[key_value[:idx]]= key_value[idx + 1:]
            except:
                params_dict[key_value] = ''
        #解码
        logger.debug(f'data请求参数1：{params_dict}')
        self.__get_url_decode(params_dict)
        logger.debug(f'data请求参数2：{params_dict}')
        return params_dict


    @relation
    def get(self, url: str = '', params: str = ''):
        """
        get请求(url传参）
        :param url:接口地址
        :param params: 接口参数（跟在url后面）
        """
        # url前缀处理
        if not url.startswith('http'):
            url = self.url + url

        res = self.session.get(url=url + "?" + params)

        self.resp = res.text
        logger.debug(f'请求结果：{self.resp}')
        # 解析请求结果（使用JSON解析结果），并将解析结果存到关联字典
        try:
            resp = self.resp[self.resp.find('{'):self.resp.rfind('}') + 1]
            self.json_resp = json.loads(resp)
            self.relations_dict.update(self.json_resp)
            return self.json_resp
        except Exception as E:
            logger.debug(E.__str__())
            self.json_resp = {}
            return self.resp

    @relation
    def post(self, url: str = '', params: str = ''):
        """
        post请求，兼容两种传参（data传参、json传参）
        :param url:接口地址
        :param params: 接口参数（理论上可传url格式或者JSON格式，这里默认JSON传参为JSON格式，data传参只支持url格式）
        """
        # url前缀处理
        if not url.startswith('http'):
            url = self.url + url
        data = None
        json_params = None
        # 存在参数则解析，不存在则为None
        if params:
            # JSON参数
            if params.startswith('{'):
                json_params = json.loads(params)
                logger.debug(f'json参数：{json_params}')
            # data参数（转换为JSON格式）
            else:
                data = self.__get_form_data(params)

        res = self.session.post(url=url, data=data, json=json_params)
        self.resp = res.text
        logger.debug(f'请求结果：{self.resp}')
        # 解析请求结果（使用JSON解析结果），并将解析结果存到关联字典
        try:
            resp = self.resp[self.resp.find('{'):self.resp.rfind('}') + 1]
            self.json_resp = json.loads(resp)
            self.relations_dict.update(self.json_resp)
            return self.json_resp
        except Exception as E:
            #非json格式
            logger.debug(E.__str__())
            self.json_resp = {}
            return self.resp

    @relation
    def addheader(self, key: str = '', val: str = ''):
        """
        添加session的头部信息
        :param key:
        :param val:
        """
        self.session.headers[key] = val
        logger.debug(f'请求头： {self.session.headers}')
        return self.session.headers

    def reauth(self):
        """定制封装（注销-获取授权信息-添加授权信息）"""
        try:

            self.post(self.url + 'logout')  # 注销
            self.post(self.url + 'auth')
            res = self.addheader('token', '{token}')
            return res
        except Exception as E:
            logger.debug(E.__str__())
            return False

    def seturl(self, url: str = ''):
        """
        设置接口地址的URL前缀
        :param url: 标准url格式
        """
        if url.startswith('http'):
            self.url = url
            if not self.url.endswith('/'):
                self.url += '/'
        logger.debug(f'请求的url前缀：{self.url}')
        return self.url

    def savejson(self, key: str = '', params_name: str = ''):
        """
        自定义关联创建，从上一步请求的json返回中，将一个键保存为关联参数
        :param key: 键
        :param params_name: 参数名
        :return:
        """
        if self.json_resp:
            self.relations_dict[params_name] = self.json_resp.get(key)
        return self.relations_dict

    @relation
    def removeheader(self, key:str = ''):
        """从会话头里删除一个键"""
        try:
            self.session.headers.pop(key)
        except Exception as e:
            logger.warning("删除头失败")
            logger.exception(e)
        return self.session.headers

    @relation
    def assertequals(self, keys: str = 'status、msg', act_resp: str = '401、用户名密码错误'):
        """
        从响应json里面，校验多个键的值
        :param keys:通过字符串的形式传递键，以'、'分割
        :param act_resp:通过字符串传递，以'、'分割
        :return:
        """
        if keys:
            keys = keys.split('、')
        else:
            logger.error(f'校验的参数传递为空： {keys} -- {act_resp}')
            return False

        if act_resp:
            act_resp = act_resp.split('、')
        else:
            logger.error(f'校验的参数传递为空： {keys} -- {act_resp}')
            return False
        for i in range(len(keys)):
            try:
                resp_val = jsonpath.jsonpath(self.json_resp,keys[i]) #不存在返回false,存在返回匹配列表
                if resp_val:
                    resp_val = resp_val[0]
                if str(resp_val) != str(act_resp[i]):
                    logger.error(f'断言失败： {keys} -- {act_resp} -- {self.json_resp}')
                    raise MyAssertError(f'断言失败： {keys} -- {act_resp} -- {self.json_resp}')
            except Exception as E:
                logger.exception(E)
                raise MyAssertError(f'断言失败： {keys} -- {act_resp} -- {self.json_resp}')
        logger.debug(f'断言成功：-- {act_resp} -- {self.json_resp}')
        return True
